using System;
using System.Collections.Generic;
using System.IO;
using Paladyne.FileSearch.Core;

namespace Paladyne.FileSearch.UI
{
    /// <summary>
    /// Breadth-first search implementation of file/directory enumerator (using queue to avoid recursion)
    /// </summary>
    public class BreadthFirstFileEnumerator : IFileEnumerator
    {
        #region IFileEnumerator Members

        /// <summary>
        /// Traverse filesystem tree in a bread-first fashion
        /// </summary>
        /// <param name="directoryInfo"></param>
        /// <param name="searchInSubdirectories"></param>
        /// <returns></returns>
        public IEnumerable<FileInfo> Enumerate(DirectoryInfo directoryInfo, bool searchInSubdirectories)
        {
            var queue = new Queue<DirectoryInfo>();
            queue.Enqueue(directoryInfo);

            while (queue.Count > 0)
            {
                DirectoryInfo directory = queue.Dequeue();

                FileInfo[] files = null;
                try
                {
                    files = directory.GetFiles();
                }
                catch (UnauthorizedAccessException)
                {
                    // Ignore inaccessible directory and its subdirectories
                    continue;
                }
                catch (DirectoryNotFoundException)
                {
                    // Ignore nonexisting directories as well
                    continue;
                }

                foreach (FileInfo file in files)
                {
                    yield return file;
                }

                if (searchInSubdirectories)
                {
                    DirectoryInfo[] directories;
                    try
                    {
                        directories = directory.GetDirectories();
                    }
                    catch (UnauthorizedAccessException)
                    {
                        // Ignore inaccessible directory and its subdirectories
                        continue;
                    }
                    catch (DirectoryNotFoundException)
                    {
                        // Ignore nonexisting directories as well
                        continue;
                    }

                    foreach (DirectoryInfo subDirectory in directories)
                    {
                        queue.Enqueue(subDirectory);
                    }
                }
            }
        }

        #endregion
    }
}